package com.hippo.core.core.manager

import android.content.Context
import android.os.Looper
import android.os.Process
import android.util.Log
import android.widget.Toast
import com.hippo.core.config.AppConfig
import com.hippo.core.utils.DateTimeUtils
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.io.Writer
import kotlin.system.exitProcess

class AppCrashHandler : Thread.UncaughtExceptionHandler {

    private var mDefaultHandler: Thread.UncaughtExceptionHandler? = null

    private var mContext: Context? = null

    private val infoGather = LinkedHashMap<String, Any>()



    companion object{
        const val TAG = "AppCrashHandler"
        fun newInstance() = AppCrashHandler()
    }

    /**
     * 初始化
     *
     * @param context
     */
    fun init(context: Context) {
        mContext = context
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler(this)
    }

    override fun uncaughtException(thread: Thread, e: Throwable) {

        Log.e(TAG, "uncaughtException: ",e)

        if (!handleException(e) && mDefaultHandler != null) {
            //如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler!!.uncaughtException(thread, e)
        } else {
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }


            //退出程序
            Process.killProcess(Process.myPid())
            exitProcess(1)
        }

    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private fun handleException(ex: Throwable?): Boolean {

        Log.e(TAG, "handleException: ", ex)

        if (ex == null) {
            return false
        }

        //使用Toast来显示异常信息
        object : Thread() {
            override fun run() {
                Looper.prepare()
                Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show()
                Looper.loop()
            }
        }.start()

        ActivityStack.popAllActivity()

        collectDeviceInfo()
        //保存日志文件
        saveCrashInfo2File(ex)
        return true
    }

    private fun collectDeviceInfo() {
        infoGather.apply {
            put("versionName", AppConfig.VERSION_NAME)
            put("versionCode", AppConfig.VERSION_CODE)
        }
    }

    /**
     * 保存错误信息到文件中
     *
     * @param ex
     * @return  返回文件名称,便于将文件传送到服务器
     */
    private fun saveCrashInfo2File(ex: Throwable): String? {

        val sb = StringBuffer()

        infoGather.forEach{ (key, value)->
            sb.append("$key=$value\n")
        }

        val writer: Writer = StringWriter()
        val printWriter = PrintWriter(writer)
        printWriter.println()
        ex.printStackTrace(printWriter)

        var cause = ex.cause
        while (cause != null) {
            cause.printStackTrace(printWriter)
            cause = cause.cause
        }
        printWriter.close()
        val result = writer.toString()
        sb.append(result)
        try {
            val time: String = DateTimeUtils.format(System.currentTimeMillis())
            val fileName = "$time.txt"
            val path = mContext?.let { FileManager.getCrashPath(it) }
            Log.e(TAG,"error path :$path")
            val input = sb.toString().byteInputStream()
            File(path, fileName).outputStream().use { output ->
                input.copyTo(output)
            }
            return fileName
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }
}